fn main() {
    println!("Hello, world!");
}

#[allow(unused_imports)]
mod test {
    use hypers::{prelude::Extract, tokio, TestClient};
    use serde::{Deserialize, Serialize};

    #[tokio::test]
    async fn test_de_request_from_query() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[query]
        struct RequestData {
            q1: String,
            q2: i64,
        }
        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v")
            .query("q1", &"q1v")
            .query("q2", &"23")
            .build();
        let data: RequestData = req.extract().await.unwrap();
        assert_eq!(
            data,
            RequestData {
                q1: "q1v".to_string(),
                q2: 23
            }
        );
    }

    #[tokio::test]
    async fn test_de_request_with_lifetime() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[query]
        struct RequestData<'a> {
            #[extract(param, query)]
            // #[body]
            q1: &'a str,
            #[extract(query)]
            #[serde(alias = "param2", alias = "param3")]
            q2: i64,
        }

        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v")
            .query("q1", &"q1v")
            .query("q2", &23)
            .build();
        let data: RequestData<'_> = req.extract().await.unwrap();
        assert_eq!(data, RequestData { q1: "q1v", q2: 23 });
    }

    #[tokio::test]
    async fn test_de_request_with_rename() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[query]
        struct RequestData<'a> {
            #[extract(param, query, rename = "abc")]
            q1: &'a str,
        }

        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v")
            .query("abc", &"q1v")
            .build();
        let data: RequestData<'_> = req.extract().await.unwrap();
        assert_eq!(data, RequestData { q1: "q1v" });
    }

    #[tokio::test]
    async fn test_de_request_with_rename_all() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[extract(query, rename_all = "PascalCase")]
        struct RequestData<'a> {
            first_name: &'a str,
            #[extract(rename = "lastName")]
            last_name: &'a str,
        }

        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v")
            .query("FirstName", &"chris")
            .query("lastName", &"young")
            .build();
        let data: RequestData<'_> = req.extract().await.unwrap();
        assert_eq!(
            data,
            RequestData {
                first_name: "chris",
                last_name: "young"
            }
        );
    }

    #[tokio::test]
    async fn test_de_request_with_multi_sources() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[query]
        struct RequestData<'a> {
            #[extract(param, alias("param1"))]
            p1: String,
            #[extract(param, alias("param2"))]
            p2: &'a str,
            #[extract(param, alias("param3"))]
            p3: usize,
            // #[query]
            q1: String,
            // #[query]
            q2: i64,
            // #[body]
            // body: RequestBody<'a>,
        }

        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v")
            .query("q1", &"q1v")
            .query("q2", &"23")
            .build();
        req.params.insert("param1".into(), "param1v".into());
        req.params.insert("p2".into(), "921".into());
        req.params.insert("p3".into(), "89785".into());
        let data: RequestData = req.extract().await.unwrap();
        assert_eq!(
            data,
            RequestData {
                p1: "param1v".into(),
                p2: "921",
                p3: 89785,
                q1: "q1v".into(),
                q2: 23
            }
        );
    }

    #[tokio::test]
    async fn test_de_request_with_json_vec() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[body]
        struct RequestData<'a> {
            #[param]
            p2: &'a str,
            users: Vec<User>,
        }
        #[derive(Deserialize, Serialize, Eq, PartialEq, Debug)]
        struct User {
            id: i64,
            name: String,
        }

        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v")
            .json(&vec![
                User {
                    id: 1,
                    name: "chris".into(),
                },
                User {
                    id: 2,
                    name: "young".into(),
                },
            ])
            .build();
        req.params.insert("p2".into(), "921".into());
        let data: RequestData = req.extract().await.unwrap();
        assert_eq!(
            data,
            RequestData {
                p2: "921",
                users: vec![
                    User {
                        id: 1,
                        name: "chris".into()
                    },
                    User {
                        id: 2,
                        name: "young".into()
                    }
                ]
            }
        );
    }

    #[tokio::test]
    async fn test_de_request_with_json_bool() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[body]
        struct RequestData<'a> {
            #[param]
            p2: &'a str,
            b: bool,
        }

        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v")
            .json(&true)
            .build();
        req.params.insert("p2".into(), "921".into());
        let data: RequestData = req.extract().await.unwrap();
        assert_eq!(data, RequestData { p2: "921", b: true });
    }

    #[tokio::test]
    async fn test_de_request_with_json_str() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[extract(body)]
        struct RequestData<'a> {
            #[extract(param)]
            p2: &'a str,
            s: &'a str,
        }

        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v")
            .json(&"abcd-good")
            .build();
        req.params.insert("p2".into(), "921".into());
        let data: RequestData = req.extract().await.unwrap();
        assert_eq!(
            data,
            RequestData {
                p2: "921",
                s: "abcd-good"
            }
        );
    }

    #[tokio::test]
    async fn test_de_request_with_form_json_str() {
        #[derive(Deserialize, Eq, PartialEq, Debug)]
        struct User<'a> {
            name: &'a str,
            age: usize,
        }
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[extract(body=json)]
        struct RequestData<'a> {
            #[param]
            p2: &'a str,
            user: User<'a>,
        }
        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v")
            .form_raw(r#"user={"name": "chris", "age": 20}"#)
            .build();
        req.params.insert("p2".into(), "921".into());
        let data: RequestData = req.extract().await.unwrap();
        assert_eq!(
            data,
            RequestData {
                p2: "921",
                user: User {
                    name: "chris",
                    age: 20
                }
            }
        );
    }

    #[tokio::test]
    async fn test_de_request_with_extract_rename_all() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[extract(rename_all = "kebab-case", query)]
        struct RequestData {
            full_name: String,
            #[extract(rename = "currAge")]
            curr_age: usize,
        }
        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v?full-name=chris+young&currAge=20")
            .build();
        let data: RequestData = req.extract().await.unwrap();
        assert_eq!(
            data,
            RequestData {
                full_name: "chris young".into(),
                curr_age: 20
            }
        );
    }

    #[tokio::test]
    async fn test_de_request_with_serde_rename_all() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[query]
        #[serde(rename_all = "kebab-case")]
        struct RequestData {
            full_name: String,
            #[extract(rename = "currAge")]
            curr_age: usize,
        }
        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v?full-name=chris+young&currAge=20")
            .build();
        let data: RequestData = req.extract().await.unwrap();
        assert_eq!(
            data,
            RequestData {
                full_name: "chris young".into(),
                curr_age: 20
            }
        );
    }

    #[tokio::test]
    async fn test_de_request_with_both_rename_all() {
        #[derive(Deserialize, Extract, Eq, PartialEq, Debug)]
        #[extract(rename_all = "kebab-case", query)]
        #[serde(rename_all = "camelCase")]
        struct RequestData {
            full_name: String,
            #[extract(rename = "currAge")]
            curr_age: usize,
        }
        let mut req = TestClient::default()
            .get("http://127.0.0.1:5800/test/1234/param2v?full-name=chris+young&currAge=20")
            .build();
        let data: RequestData = req.extract().await.unwrap();
        assert_eq!(
            data,
            RequestData {
                full_name: "chris young".into(),
                curr_age: 20
            }
        );
    }
}
